package com.cencat.merchant.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cencat.common.enums.ErrorCode;
import com.cencat.common.enums.UserStatus;
import com.cencat.common.exception.BusinessException;
import com.cencat.common.utils.CencatStringUtils;
import com.cencat.merchant.entity.MerchantUser;
import com.cencat.merchant.mapper.MerchantUserMapper;
import com.cencat.merchant.service.MerchantUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 商家用户服务实现类
 * @author cencat
 * @since 2024-01-01
 */
@Service
@Slf4j
public class MerchantUserServiceImpl implements MerchantUserService {

    @Autowired
    private MerchantUserMapper merchantUserMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createMerchantUser(MerchantUser merchantUser) throws BusinessException {
        if (merchantUser == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 校验必填字段
        if (CencatStringUtils.isBlank(merchantUser.getUsername()) ||
            CencatStringUtils.isBlank(merchantUser.getPassword()) ||
            merchantUser.getMerchantId() == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 检查用户名是否已存在
        MerchantUser existingUser = merchantUserMapper.selectByUsername(merchantUser.getUsername());
        if (existingUser != null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 检查邮箱是否已存在
        if (CencatStringUtils.isNotBlank(merchantUser.getEmail())) {
            MerchantUser existingEmailUser = merchantUserMapper.selectByEmail(merchantUser.getEmail());
            if (existingEmailUser != null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }
        }

        // 检查手机号是否已存在
        if (CencatStringUtils.isNotBlank(merchantUser.getPhone())) {
            MerchantUser existingPhoneUser = merchantUserMapper.selectByPhone(merchantUser.getPhone());
            if (existingPhoneUser != null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }
        }

        // 密码加密
        merchantUser.setPassword(passwordEncoder.encode(merchantUser.getPassword()));

        // 设置默认值
        merchantUser.setStatus(UserStatus.NORMAL); // 启用状态
        merchantUser.setCreateTime(LocalDateTime.now());
        merchantUser.setUpdateTime(LocalDateTime.now());

        int result = merchantUserMapper.insert(merchantUser);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        return merchantUser.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateMerchantUser(MerchantUser merchantUser) throws BusinessException {
        if (merchantUser == null || merchantUser.getId() == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser existingUser = merchantUserMapper.selectById(merchantUser.getId());
        if (existingUser == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 检查用户名是否被其他用户使用
        if (CencatStringUtils.isNotBlank(merchantUser.getUsername()) &&
            !merchantUser.getUsername().equals(existingUser.getUsername())) {
            MerchantUser duplicateUser = merchantUserMapper.selectByUsername(merchantUser.getUsername());
            if (duplicateUser != null && !duplicateUser.getId().equals(merchantUser.getId())) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }
        }

        // 检查邮箱是否被其他用户使用
        if (CencatStringUtils.isNotBlank(merchantUser.getEmail()) &&
            !merchantUser.getEmail().equals(existingUser.getEmail())) {
            MerchantUser duplicateEmailUser = merchantUserMapper.selectByEmail(merchantUser.getEmail());
            if (duplicateEmailUser != null && !duplicateEmailUser.getId().equals(merchantUser.getId())) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }
        }

        // 检查手机号是否被其他用户使用
        if (CencatStringUtils.isNotBlank(merchantUser.getPhone()) &&
            !merchantUser.getPhone().equals(existingUser.getPhone())) {
            MerchantUser duplicatePhoneUser = merchantUserMapper.selectByPhone(merchantUser.getPhone());
            if (duplicatePhoneUser != null && !duplicatePhoneUser.getId().equals(merchantUser.getId())) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }
        }

        merchantUser.setUpdateTime(LocalDateTime.now());
        int result = merchantUserMapper.updateById(merchantUser);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteMerchantUser(Long userId) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser existingUser = merchantUserMapper.selectById(userId);
        if (existingUser == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        int result = merchantUserMapper.deleteById(userId);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        return true;
    }

    @Override
    public MerchantUser getMerchantUserById(Long userId) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        return merchantUserMapper.selectById(userId);
    }

    @Override
    public MerchantUser getMerchantUserByUsername(String username) throws BusinessException {
        if (CencatStringUtils.isBlank(username)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        return merchantUserMapper.selectByUsername(username);
    }

    @Override
    public MerchantUser getMerchantUserByEmail(String email) throws BusinessException {
        if (CencatStringUtils.isBlank(email)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        return merchantUserMapper.selectByEmail(email);
    }

    @Override
    public MerchantUser getMerchantUserByPhone(String phone) throws BusinessException {
        if (CencatStringUtils.isBlank(phone)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        return merchantUserMapper.selectByPhone(phone);
    }

    @Override
    public List<MerchantUser> getMerchantUsersByMerchantId(Long merchantId) {
        if (merchantId == null || merchantId <= 0) {
            return List.of();
        }

        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MerchantUser::getMerchantId, merchantId)
                   .orderByDesc(MerchantUser::getCreateTime);

        return merchantUserMapper.selectList(queryWrapper);
    }

    @Override
    public IPage<MerchantUser> getMerchantUserPage(Page<MerchantUser> page,
                                                  Long tenantId,
                                                  Long merchantId,
                                                  String username,
                                                  String realName,
                                                  String phone,
                                                  String status) {
        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        
        if (tenantId != null) {
            queryWrapper.eq(MerchantUser::getTenantId, tenantId);
        }
        if (merchantId != null) {
            queryWrapper.eq(MerchantUser::getMerchantId, merchantId);
        }
        if (CencatStringUtils.isNotBlank(username)) {
            queryWrapper.like(MerchantUser::getUsername, username);
        }
        if (CencatStringUtils.isNotBlank(realName)) {
            queryWrapper.like(MerchantUser::getRealName, realName);
        }
        if (CencatStringUtils.isNotBlank(phone)) {
            queryWrapper.like(MerchantUser::getPhone, phone);
        }
        if (CencatStringUtils.isNotBlank(status)) {
            queryWrapper.eq(MerchantUser::getStatus, status);
        }
        
        queryWrapper.orderByDesc(MerchantUser::getCreateTime);
        
        return merchantUserMapper.selectPage(page, queryWrapper);
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public MerchantUser login(String username, String password) throws BusinessException {
        if (CencatStringUtils.isBlank(username) || CencatStringUtils.isBlank(password)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser user = merchantUserMapper.selectByUsername(username);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        if (user.getStatus() != UserStatus.NORMAL) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 更新登录信息
        merchantUserMapper.updateLoginInfo(user.getId(), LocalDateTime.now(), null);

        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changePassword(Long userId, String oldPassword, String newPassword) throws BusinessException {
        if (userId == null || userId <= 0 ||
            CencatStringUtils.isBlank(oldPassword) ||
            CencatStringUtils.isBlank(newPassword)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser user = merchantUserMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        String encodedNewPassword = passwordEncoder.encode(newPassword);
        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getPassword, encodedNewPassword)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPassword(Long userId, String newPassword) throws BusinessException {
        if (userId == null || userId <= 0 || CencatStringUtils.isBlank(newPassword)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser user = merchantUserMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        String encodedNewPassword = passwordEncoder.encode(newPassword);
        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getPassword, encodedNewPassword)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean enableUser(Long userId) throws BusinessException {
        return updateUserStatus(userId, 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean disableUser(Long userId) throws BusinessException {
        return updateUserStatus(userId, 0);
    }









    /**
     * 添加缺失的接口方法实现
     */

    @Transactional(rollbackFor = Exception.class)
    public Boolean updateLastLoginTime(Long userId) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        merchantUserMapper.updateLoginInfo(userId, LocalDateTime.now(), null);
        return true;
    }

    /**
     * 更新用户状态
     * @param userId 用户ID
     * @param status 状态
     * @return 是否成功
     */
    private Boolean updateUserStatus(Long userId, Integer status) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser existingUser = merchantUserMapper.selectById(userId);
        if (existingUser == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getStatus, status)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setUserPermissions(Long userId, List<String> permissions) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser existingUser = merchantUserMapper.selectById(userId);
        if (existingUser == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 这里可以实现权限设置逻辑，比如更新用户权限表
        // 暂时返回true，具体实现根据业务需求
        log.info("设置用户权限: userId={}, permissions={}", userId, permissions);
        
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setUserRoles(Long userId, List<Long> roleIds) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser existingUser = merchantUserMapper.selectById(userId);
        if (existingUser == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        // 将角色ID列表转换为字符串存储
        String roleIdsStr = roleIds != null ? String.join(",", roleIds.stream().map(String::valueOf).toArray(String[]::new)) : "";
        
        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getRoleIds, roleIdsStr)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }

        log.info("设置用户角色成功: userId={}, roleIds={}", userId, roleIds);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateLoginInfo(Long userId, String loginIp) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getLastLoginTime, LocalDateTime.now())
                    .set(MerchantUser::getLastLoginIp, loginIp)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        return result > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean lockUser(Long userId, Integer lockMinutes) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        LocalDateTime lockTime = lockMinutes != null ? LocalDateTime.now().plusMinutes(lockMinutes) : LocalDateTime.now().plusHours(24);
        
        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getLockTime, lockTime)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        return result > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean unlockUser(Long userId) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getLockTime, null)
                    .set(MerchantUser::getPasswordErrorCount, 0)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        return result > 0;
    }

    @Override
    public Boolean checkUsernameExists(String username, Long excludeId) {
        if (CencatStringUtils.isBlank(username)) {
            return false;
        }

        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MerchantUser::getUsername, username);
        if (excludeId != null) {
            queryWrapper.ne(MerchantUser::getId, excludeId);
        }

        return merchantUserMapper.selectCount(queryWrapper) > 0;
    }

    @Override
    public Boolean checkPhoneExists(String phone, Long excludeId) {
        if (CencatStringUtils.isBlank(phone)) {
            return false;
        }

        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MerchantUser::getPhone, phone);
        if (excludeId != null) {
            queryWrapper.ne(MerchantUser::getId, excludeId);
        }

        return merchantUserMapper.selectCount(queryWrapper) > 0;
    }

    @Override
    public Boolean checkEmailExists(String email, Long excludeId) {
        if (CencatStringUtils.isBlank(email)) {
            return false;
        }

        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MerchantUser::getEmail, email);
        if (excludeId != null) {
            queryWrapper.ne(MerchantUser::getId, excludeId);
        }

        return merchantUserMapper.selectCount(queryWrapper) > 0;
    }

    @Override
    public Boolean verifyPassword(String rawPassword, String encodedPassword, String salt) {
        if (CencatStringUtils.isBlank(rawPassword) || CencatStringUtils.isBlank(encodedPassword)) {
            return false;
        }
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    @Override
    public String encodePassword(String rawPassword, String salt) {
        if (CencatStringUtils.isBlank(rawPassword)) {
            return null;
        }
        return passwordEncoder.encode(rawPassword);
    }

    @Override
    public String generateSalt() {
        return CencatStringUtils.generateRandomString(16);
    }

    @Override
    public Long countUsersByMerchantId(Long merchantId) {
        if (merchantId == null) {
            return 0L;
        }

        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MerchantUser::getMerchantId, merchantId);
        return merchantUserMapper.selectCount(queryWrapper);
    }

    @Override
    public java.util.Map<String, Long> countUsersByStatus(Long merchantId) {
        // 这里可以实现按状态统计用户数量的逻辑
        // 暂时返回空Map
        return new java.util.HashMap<>();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public java.util.Map<String, Object> batchImportUsers(List<MerchantUser> users, Long merchantId) throws BusinessException {
        // 这里可以实现批量导入用户的逻辑
        // 暂时返回空Map
        return new java.util.HashMap<>();
    }

    @Override
    public List<MerchantUser> exportUsers(Long merchantId, List<Long> userIds) {
        if (merchantId == null) {
            return new java.util.ArrayList<>();
        }

        LambdaQueryWrapper<MerchantUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MerchantUser::getMerchantId, merchantId);
        if (userIds != null && !userIds.isEmpty()) {
            queryWrapper.in(MerchantUser::getId, userIds);
        }

        return merchantUserMapper.selectList(queryWrapper);
    }

    @Override
    public Boolean isUserLocked(Long userId) {
        if (userId == null) {
            return false;
        }

        MerchantUser user = merchantUserMapper.selectById(userId);
        if (user == null || user.getLockTime() == null) {
            return false;
        }

        return user.getLockTime().isAfter(LocalDateTime.now());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer incrementPasswordErrorCount(Long userId) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        MerchantUser user = merchantUserMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        Integer errorCount = user.getPasswordErrorCount() != null ? user.getPasswordErrorCount() + 1 : 1;
        
        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getPasswordErrorCount, errorCount)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        merchantUserMapper.update(null, updateWrapper);
        return errorCount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean clearPasswordErrorCount(Long userId) throws BusinessException {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        LambdaUpdateWrapper<MerchantUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MerchantUser::getId, userId)
                    .set(MerchantUser::getPasswordErrorCount, 0)
                    .set(MerchantUser::getUpdateTime, LocalDateTime.now());

        int result = merchantUserMapper.update(null, updateWrapper);
        return result > 0;
    }
}